{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Import the required modules."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "1fJk7zmMjcFm"
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "import seaborn as sns; sns.set()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "MOKVbdzBjlmP"
   },
   "outputs": [],
   "source": [
    "from keras.models import Sequential, load_model\n",
    "from keras.layers import Dense, LSTM, Bidirectional\n",
    "from keras.utils import plot_model\n",
    "from keras.utils.np_utils import to_categorical\n",
    "from keras.utils import np_utils\n",
    "\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.preprocessing import LabelEncoder, StandardScaler\n",
    "from sklearn.metrics import confusion_matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# number_of_samples determine how many samples from the attack and normal dataset should be read and used."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "u7H2jNs1csN2"
   },
   "outputs": [],
   "source": [
    "number_of_samples = 50000"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Read data from attack and normal datasets."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "WkSbWhYPjpdP"
   },
   "outputs": [],
   "source": [
    "data_attack = pd.read_csv('../../dataset/dataset_attack.csv', nrows = number_of_samples)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "MlnVmtsDj0Af"
   },
   "outputs": [],
   "source": [
    "data_normal = pd.read_csv('../../dataset/dataset_normal.csv', nrows = number_of_samples)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "kMoOG1gDj1eJ"
   },
   "outputs": [],
   "source": [
    "data_normal.columns=[ 'frame.len', 'frame.protocols', 'ip.hdr_len',\n",
    "       'ip.len', 'ip.flags.rb', 'ip.flags.df', 'p.flags.mf', 'ip.frag_offset',\n",
    "       'ip.ttl', 'ip.proto', 'ip.src', 'ip.dst', 'tcp.srcport', 'tcp.dstport',\n",
    "       'tcp.len', 'tcp.ack', 'tcp.flags.res', 'tcp.flags.ns', 'tcp.flags.cwr',\n",
    "       'tcp.flags.ecn', 'tcp.flags.urg', 'tcp.flags.ack', 'tcp.flags.push',\n",
    "       'tcp.flags.reset', 'tcp.flags.syn', 'tcp.flags.fin', 'tcp.window_size',\n",
    "       'tcp.time_delta','class']\n",
    "data_attack.columns=[ 'frame.len', 'frame.protocols', 'ip.hdr_len',\n",
    "       'ip.len', 'ip.flags.rb', 'ip.flags.df', 'p.flags.mf', 'ip.frag_offset',\n",
    "       'ip.ttl', 'ip.proto', 'ip.src', 'ip.dst', 'tcp.srcport', 'tcp.dstport',\n",
    "       'tcp.len', 'tcp.ack', 'tcp.flags.res', 'tcp.flags.ns', 'tcp.flags.cwr',\n",
    "       'tcp.flags.ecn', 'tcp.flags.urg', 'tcp.flags.ack', 'tcp.flags.push',\n",
    "       'tcp.flags.reset', 'tcp.flags.syn', 'tcp.flags.fin', 'tcp.window_size',\n",
    "       'tcp.time_delta','class']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Drop unwanted columns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "13n5FKSJj4Fn"
   },
   "outputs": [],
   "source": [
    "data_normal=data_normal.drop(['ip.src', 'ip.dst','frame.protocols'],axis=1)\n",
    "data_attack=data_attack.drop(['ip.src', 'ip.dst','frame.protocols'],axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "EdgboyqDj-AJ"
   },
   "outputs": [],
   "source": [
    "features=[ 'frame.len', 'ip.hdr_len',\n",
    "       'ip.len', 'ip.flags.rb', 'ip.flags.df', 'p.flags.mf', 'ip.frag_offset',\n",
    "       'ip.ttl', 'ip.proto', 'tcp.srcport', 'tcp.dstport',\n",
    "       'tcp.len', 'tcp.ack', 'tcp.flags.res', 'tcp.flags.ns', 'tcp.flags.cwr',\n",
    "       'tcp.flags.ecn', 'tcp.flags.urg', 'tcp.flags.ack', 'tcp.flags.push',\n",
    "       'tcp.flags.reset', 'tcp.flags.syn', 'tcp.flags.fin', 'tcp.window_size',\n",
    "       'tcp.time_delta']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "7IxNpgX5kAMg"
   },
   "outputs": [],
   "source": [
    "X_normal= data_normal[features].values\n",
    "X_attack= data_attack[features].values\n",
    "Y_normal= data_normal['class']\n",
    "Y_attack= data_attack['class']\n",
    "X=np.concatenate((X_normal,X_attack))\n",
    "Y=np.concatenate((Y_normal,Y_attack))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Standardise the data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "b3xIr2rRkWMX"
   },
   "outputs": [],
   "source": [
    "scalar = StandardScaler(copy=True, with_mean=True, with_std=True)\n",
    "scalar.fit(X)\n",
    "X = scalar.transform(X)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# the class field, replace value 'attack' with 0 and 'normal' with 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "0U1VeOtEkYBX"
   },
   "outputs": [],
   "source": [
    "for i in range(0,len(Y)):\n",
    "  if Y[i] ==\"attack\":\n",
    "    Y[i]=0\n",
    "  else:\n",
    "    Y[i]=1\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After feature transformation, we get a 𝑚×𝑛' matrix, where 𝑚 indicates the number of packets and 𝑛' indicates the number of new features after transformation. In order to learn patterns in both long and short term, we use a sliding window to separate continuous packets and reshape the data into a series of time windows with window size 𝑇. The label 𝑦 in each window illustrates the last packet. After reshaping, we have a three-dimensional matrix with shape (𝑚−𝑇 )×𝑇 ×𝑛'. Figure illustrates the workflow of feature extraction, transformation, and reshaping.\n",
    "![dataset transformation](feature_extraction.png)\n",
    "In this way, we change the features from conventional packet-based to window-based, by which we can learn network patterns from both previous (𝑇 −1) packets and current packet."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "PEK_22RTkrvH"
   },
   "outputs": [],
   "source": [
    "features = len(X[0])\n",
    "samples = X.shape[0]\n",
    "train_len = 25\n",
    "input_len = samples - train_len\n",
    "I = np.zeros((samples - train_len, train_len, features))\n",
    "\n",
    "for i in range(input_len):\n",
    "    temp = np.zeros((train_len, features))\n",
    "    for j in range(i, i + train_len - 1):\n",
    "        temp[j-i] = X[j]\n",
    "    I[i] = temp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(100000, 25)"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "1l5ft9AblBln"
   },
   "outputs": [],
   "source": [
    "X_train, X_test, Y_train, Y_test = train_test_split(I, Y[25:100000], test_size = 0.2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The architecture used is \n",
    "![Model](model_brnn.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "SzHoR1ewdODm"
   },
   "outputs": [],
   "source": [
    "def create_baseline():\n",
    "    model = Sequential()\n",
    "    \n",
    "    model.add(Bidirectional(LSTM(64, activation='tanh', kernel_regularizer='l2')))\n",
    "    model.add(Dense(128, activation = 'relu', kernel_regularizer='l2'))\n",
    "    model.add(Dense(1, activation = 'sigmoid', kernel_regularizer='l2'))\n",
    "    \n",
    "    model.compile(loss = 'binary_crossentropy', optimizer = 'adam', metrics = ['accuracy'])\n",
    "    \n",
    "    return model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "fW-zMrYFdVP9"
   },
   "outputs": [],
   "source": [
    "model = create_baseline()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "d6nUrwGNdYUP"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 63984 samples, validate on 15996 samples\n",
      "Epoch 1/40\n",
      "63984/63984 [==============================] - 54s 837us/step - loss: 0.1943 - acc: 0.9508 - val_loss: 0.1648 - val_acc: 0.9561\n",
      "Epoch 2/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1598 - acc: 0.9605 - val_loss: 0.1495 - val_acc: 0.9684\n",
      "Epoch 3/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1522 - acc: 0.9615 - val_loss: 0.1526 - val_acc: 0.9612\n",
      "Epoch 4/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1402 - acc: 0.9642 - val_loss: 0.1516 - val_acc: 0.9682\n",
      "Epoch 5/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1344 - acc: 0.9661 - val_loss: 0.1179 - val_acc: 0.9725\n",
      "Epoch 6/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1327 - acc: 0.9667 - val_loss: 0.1264 - val_acc: 0.9686\n",
      "Epoch 7/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1228 - acc: 0.9691 - val_loss: 0.1114 - val_acc: 0.9729\n",
      "Epoch 8/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1252 - acc: 0.9683 - val_loss: 0.1365 - val_acc: 0.9614\n",
      "Epoch 9/40\n",
      "63984/63984 [==============================] - 53s 835us/step - loss: 0.1199 - acc: 0.9698 - val_loss: 0.1090 - val_acc: 0.9737\n",
      "Epoch 10/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1216 - acc: 0.9692 - val_loss: 0.1159 - val_acc: 0.9738\n",
      "Epoch 11/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1221 - acc: 0.9679 - val_loss: 0.1216 - val_acc: 0.9675\n",
      "Epoch 12/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1191 - acc: 0.9706 - val_loss: 0.1182 - val_acc: 0.9719\n",
      "Epoch 13/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1132 - acc: 0.9717 - val_loss: 0.1074 - val_acc: 0.9724\n",
      "Epoch 14/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1127 - acc: 0.9718 - val_loss: 0.1121 - val_acc: 0.9713\n",
      "Epoch 15/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1115 - acc: 0.9720 - val_loss: 0.1038 - val_acc: 0.9748\n",
      "Epoch 16/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1121 - acc: 0.9718 - val_loss: 0.1184 - val_acc: 0.9750\n",
      "Epoch 17/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1108 - acc: 0.9729 - val_loss: 0.1169 - val_acc: 0.9752\n",
      "Epoch 18/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1104 - acc: 0.9723 - val_loss: 0.1036 - val_acc: 0.9752\n",
      "Epoch 19/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1081 - acc: 0.9728 - val_loss: 0.1051 - val_acc: 0.9732\n",
      "Epoch 20/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1078 - acc: 0.9736 - val_loss: 0.0994 - val_acc: 0.9766\n",
      "Epoch 21/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1091 - acc: 0.9731 - val_loss: 0.1076 - val_acc: 0.9739\n",
      "Epoch 22/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1042 - acc: 0.9746 - val_loss: 0.1019 - val_acc: 0.9749\n",
      "Epoch 23/40\n",
      "63984/63984 [==============================] - 53s 832us/step - loss: 0.1049 - acc: 0.9741 - val_loss: 0.1135 - val_acc: 0.9721\n",
      "Epoch 24/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1099 - acc: 0.9725 - val_loss: 0.1022 - val_acc: 0.9771\n",
      "Epoch 25/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1078 - acc: 0.9735 - val_loss: 0.0944 - val_acc: 0.9786\n",
      "Epoch 26/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1055 - acc: 0.9737 - val_loss: 0.1126 - val_acc: 0.9764\n",
      "Epoch 27/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1062 - acc: 0.9739 - val_loss: 0.1007 - val_acc: 0.9769\n",
      "Epoch 28/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1069 - acc: 0.9736 - val_loss: 0.0956 - val_acc: 0.9783\n",
      "Epoch 29/40\n",
      "63984/63984 [==============================] - 53s 835us/step - loss: 0.0986 - acc: 0.9756 - val_loss: 0.0963 - val_acc: 0.9771\n",
      "Epoch 30/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.0992 - acc: 0.9757 - val_loss: 0.1088 - val_acc: 0.9709\n",
      "Epoch 31/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1109 - acc: 0.9724 - val_loss: 0.0935 - val_acc: 0.9796\n",
      "Epoch 32/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.1003 - acc: 0.9766 - val_loss: 0.0949 - val_acc: 0.9801\n",
      "Epoch 33/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.1013 - acc: 0.9760 - val_loss: 0.0910 - val_acc: 0.9786\n",
      "Epoch 34/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.0981 - acc: 0.9764 - val_loss: 0.1299 - val_acc: 0.9681\n",
      "Epoch 35/40\n",
      "63984/63984 [==============================] - 53s 833us/step - loss: 0.0958 - acc: 0.9767 - val_loss: 0.0959 - val_acc: 0.9776\n",
      "Epoch 36/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.0963 - acc: 0.9779 - val_loss: 0.0987 - val_acc: 0.9783\n",
      "Epoch 37/40\n",
      "63984/63984 [==============================] - 53s 835us/step - loss: 0.0973 - acc: 0.9775 - val_loss: 0.0879 - val_acc: 0.9784\n",
      "Epoch 38/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.0936 - acc: 0.9787 - val_loss: 0.0866 - val_acc: 0.9792\n",
      "Epoch 39/40\n",
      "63984/63984 [==============================] - 53s 834us/step - loss: 0.0901 - acc: 0.9794 - val_loss: 0.0870 - val_acc: 0.9801\n",
      "Epoch 40/40\n",
      "52480/63984 [=======================>......] - ETA: 9s - loss: 0.1000 - acc: 0.9768"
     ]
    }
   ],
   "source": [
    "history = model.fit(X_train, Y_train, epochs = 40,validation_split=0.2, verbose = 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Obtained plot of accuracy\n",
    "\n",
    "![plot of accuracy](BRNN_Model_Accuracy.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "7dR8MHphk68X"
   },
   "outputs": [],
   "source": [
    "# Plot training & validation accuracy values\n",
    "plt.plot(history.history['acc'])\n",
    "plt.plot(history.history['val_acc'])\n",
    "plt.title('BRNN Model Accuracy')\n",
    "plt.ylabel('Accuracy')\n",
    "plt.xlabel('Epoch')\n",
    "plt.legend(['Train', 'Test'], loc='lower right')\n",
    "plt.savefig('BRNN Model Accuracy.png')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Plot of loss\n",
    "![plot of loss](BRNN_Model_Loss.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "eKjMDYIOk72N"
   },
   "outputs": [],
   "source": [
    "# Plot training & validation loss values\n",
    "plt.plot(history.history['loss'])\n",
    "plt.plot(history.history['val_loss'])\n",
    "plt.title('BRNN Model  Loss')\n",
    "plt.ylabel('Loss')\n",
    "plt.xlabel('Epoch')\n",
    "plt.legend(['Train', 'Test'], loc='upper left')\n",
    "plt.savefig('BRNN Model Loss.png')\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "heMaPerEdn3c"
   },
   "outputs": [],
   "source": [
    "predict = model.predict(X_test, verbose=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#  Calculate True positive,True negetive,False positive and False negetive values. Create Heatmap."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "rAjFgVm6uGGp"
   },
   "outputs": [],
   "source": [
    "tp = 0\n",
    "tn = 0\n",
    "fp = 0\n",
    "fn = 0\n",
    "predictn = predict.flatten().round()\n",
    "predictn = predictn.tolist()\n",
    "Y_testn = Y_test.tolist()\n",
    "for i in range(len(Y_testn)):\n",
    "  if predictn[i]==1 and Y_testn[i]==1:\n",
    "    tp+=1\n",
    "  elif predictn[i]==0 and Y_testn[i]==0:\n",
    "    tn+=1\n",
    "  elif predictn[i]==0 and Y_testn[i]==1:\n",
    "    fp+=1\n",
    "  elif predictn[i]==1 and Y_testn[i]==0:\n",
    "    fn+=1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 274
    },
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 949,
     "status": "ok",
     "timestamp": 1557862375571,
     "user": {
      "displayName": "Mohammed Musthafa",
      "photoUrl": "",
      "userId": "16090542423726450957"
     },
     "user_tz": -330
    },
    "id": "0Ad719yjxPL2",
    "outputId": "972ee841-76cd-49f9-f0c7-6961170aae8c"
   },
   "outputs": [],
   "source": [
    "to_heat_map =[[tn,fp],[fn,tp]]\n",
    "to_heat_map = pd.DataFrame(to_heat_map, index = [\"Attack\",\"Normal\"],columns = [\"Attack\",\"Normal\"])\n",
    "ax = sns.heatmap(to_heat_map,annot=True, fmt=\"d\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Save details "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "rMBI_fKCzQBN"
   },
   "outputs": [],
   "source": [
    "figure = ax.get_figure()    \n",
    "figure.savefig('confusion_matrix_BRNN.png', dpi=400)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "mdcKrPWEfE44"
   },
   "outputs": [],
   "source": [
    "model.save('brnn_model.h5')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "mv1vi3_KfPHE"
   },
   "outputs": [],
   "source": [
    "scores = model.evaluate(X_test, Y_test, verbose=0)\n",
    "print(\"%s: %.2f%%\" % (model.metrics_names[1], scores[1]*100))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "brnn_classifier",
   "provenance": [],
   "version": "0.3.2"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
